#include <jni.h>
#include "DocumentMemory.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "extr_api.h"

/*
 * Class:     DocumentMemory
 * Method:    CreateDocumentMemory_helper
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_CreateDocumentMemory_1helper
  (JNIEnv *env, jobject obj)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	void  *DocumentMemory;
	int ErrorCode;

	fid = (*env)->GetFieldID(env, cls, "lng_document_mem_ptr", "J");
	if (fid == 0)
	{
		return -1;
	}
	
	ErrorCode = ExtrCreateDocumentMemory(&DocumentMemory);
	if (ErrorCode != 0)
	{
		return ErrorCode;
	}
	
	(*env)->SetLongField(env, obj, fid, (long)DocumentMemory);

	return ErrorCode;
}

/*
 * Class:     DocumentMemory
 * Method:    ClearDocumentMemory_helper
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_ClearDocumentMemory_1helper
  (JNIEnv *env, jobject obj, jlong DocMem)
{
	return ExtrClearDocumentMemory((void *)DocMem);
}

/*
 * Class:     DocumentMemory
 * Method:    GetErrorMessage_helper
 * Signature: (I)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_DocumentMemory_GetErrorMessage_1helper
  (JNIEnv *env, jobject obj, jint ErrorCode)
{
	char *ErrorMessage;
	ExtrGetErrorMessage(ErrorCode, &ErrorMessage);
	return (*env)->NewStringUTF(env, ErrorMessage);
}

/*
 * Class:     DocumentMemory
 * Method:    ActivateHighlights_helper
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_ActivateHighlights_1helper
  (JNIEnv *env, jobject obj, jlong DocMem)
{
	return ExtrActivateHighlights((void *)DocMem);
}

/*
 * Class:     DocumentMemory
 * Method:    ActivateHTMLFilter_helper
 * Signature: (JJ)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_ActivateHTMLFilter_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jlong StopMem)
{
	return ExtrActivateHTMLFilter((void *)DocMem, (void *)StopMem);
}

/*
 * Class:     DocumentMemory
 * Method:    ActivateEmailFilter_helper
 * Signature: (JJ)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_ActivateEmailFilter_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jlong StopMem)
{
	return ExtrActivateEmailFilter((void *)DocMem, (void *)StopMem);
}

/*
 * Class:     DocumentMemory
 * Method:    SetInputCode_helper
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SetInputCode_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint CharCodeID)

{
	return ExtrSetInputCode((void *)DocMem, CharCodeID);
}

/*
 * Class:     DocumentMemory
 * Method:    SetOutputCode_helper
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SetOutputCode_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint CharCodeID)
{
	return ExtrSetOutputCode((void *)DocMem, CharCodeID);
}

/*
 * Class:     DocumentMemory
 * Method:    SetDocumentLanguage_helper
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SetDocumentLanguage_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint LanguageID)
{
	return ExtrSetDocumentLanguage((void *)DocMem, LanguageID);
}

/*
 * Class:     DocumentMemory
 * Method:    SetNumberPhrases_helper
 * Signature: (JD)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SetNumberPhrases_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jdouble DesiredNumber)
{
	return ExtrSetNumberPhrases((void *)DocMem, DesiredNumber);
}

/*
 * Class:     DocumentMemory
 * Method:    SetHighlightType_helper
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SetHighlightType_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint HighlightType)
{
	return ExtrSetHighlightType((void *)DocMem, HighlightType);
}

/*
 * Class:     DocumentMemory
 * Method:    ReadDocumentBuffer_helper
 * Signature: (JJ[B)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_ReadDocumentBuffer_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jlong StopMem, jbyteArray DocBuffer)
{
	int int_buf_len = (*env)->GetArrayLength(env, DocBuffer);
	jbyte *str_DocBuffer = (*env)->GetByteArrayElements(env, DocBuffer, 0); // jbyte = char
	int ErrorCode = ExtrReadDocumentBuffer((void *)DocMem, (void *)StopMem, (void *)str_DocBuffer, int_buf_len);
	(*env)->ReleaseByteArrayElements(env, DocBuffer, str_DocBuffer, 0);
	return ErrorCode;
}

/*
 * Class:     DocumentMemory
 * Method:    SignalDocumentEnd_helper
 * Signature: (JJ)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_SignalDocumentEnd_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jlong StopMem)
{
	return ExtrSignalDocumentEnd((void *)DocMem, (void *)StopMem);
}

/*
 * Class:     DocumentMemory
 * Method:    GetPhraseListSize_helper
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_GetPhraseListSize_1helper
  (JNIEnv *env, jobject obj, jlong DocMem)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode;
	int int_PhraseListSize;

	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return -1;
	}
	
	ErrorCode = ExtrGetPhraseListSize((void *)DocMem, &int_PhraseListSize);
	(*env)->SetIntField(env, obj, fid, ErrorCode); // set error code

	if (ErrorCode != 0)
	{	// ensure something is returned
		return -1;
	}
	
	return int_PhraseListSize;
}

/*
 * Class:     DocumentMemory
 * Method:    GetPhraseByIndex_helper
 * Signature: (JI)[B
 */
JNIEXPORT jbyteArray JNICALL Java_DocumentMemory_GetPhraseByIndex_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint index)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode, OutputCode, NumberBytes, i;
	void *Phrase;
	char *SingleBytePhrase;
	unsigned short int *DoubleBytePhrase;
	jbyteArray arr_return;

	fid = (*env)->GetFieldID(env, cls, "int_output_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return NULL;
	}
	OutputCode = (*env)->GetIntField(env, obj, fid); // get the output character code
	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return NULL;
	}
	
	ErrorCode = ExtrGetPhraseByIndex((void *)DocMem, index, (void **)&Phrase);
	(*env)->SetIntField(env, obj, fid, ErrorCode); // set error code

	if (ErrorCode != 0)
	{	// ensure something is returned
		return NULL;
	}

	if (OutputCode == 2)
	{	// unicode code case
		DoubleBytePhrase = (unsigned short int*) Phrase;
		for (i = 0; DoubleBytePhrase[i] != 0; i++); // get number of character
		NumberBytes = i * 2; // get the number of bytes
	}
	else
	{
		NumberBytes = strlen((char *)Phrase);
	}


	SingleBytePhrase = (char *) Phrase;
	
	arr_return = (*env)->NewByteArray(env, NumberBytes);
	(*env)->SetByteArrayRegion(env, arr_return, 0, NumberBytes, SingleBytePhrase);

	return arr_return;
}

/*
 * Class:     DocumentMemory
 * Method:    GetScoreByIndex_helper
 * Signature: (JI)D
 */
JNIEXPORT jdouble JNICALL Java_DocumentMemory_GetScoreByIndex_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint index)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode;
	double dbl_score;

	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return -1;
	}
	
	ErrorCode = ExtrGetScoreByIndex((void *)DocMem, index, &dbl_score);
	(*env)->SetIntField(env, obj, fid, ErrorCode);

	if (ErrorCode != 0)
	{	// ensure something is returned.
		return -1;
	}
	return dbl_score;
}

/*
 * Class:     DocumentMemory
 * Method:    GetDocumentLanguage_helper
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_GetDocumentLanguage_1helper
  (JNIEnv *env, jobject obj, jlong DocMem)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode;
	int int_LanguageID;

	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return -1;
	}
	
	ErrorCode = ExtrGetDocumentLanguage((void *)DocMem, &int_LanguageID);
	(*env)->SetIntField(env, obj, fid, ErrorCode);

	if (ErrorCode != 0)
	{	// ensure something is returned
		return -1;
	}
	
	return int_LanguageID;
}

/*
 * Class:     DocumentMemory
 * Method:    GetHighlightListSize_helper
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_DocumentMemory_GetHighlightListSize_1helper
  (JNIEnv *env, jobject obj, jlong DocMem)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode;
	int int_HighlightListSize = -1;

	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return -1;
	}
	
	ErrorCode = ExtrGetHighlightListSize((void *)DocMem, &int_HighlightListSize);
	(*env)->SetIntField(env, obj, fid, ErrorCode);

	if (ErrorCode != 0)
	{	// ensure something is returned
		return -1;
	}
	
	return int_HighlightListSize;
}


/*
 * Class:     DocumentMemory
 * Method:    GetHighlightByIndex_helper
 * Signature: (JI)[B
 */
JNIEXPORT jbyteArray JNICALL Java_DocumentMemory_GetHighlightByIndex_1helper
  (JNIEnv *env, jobject obj, jlong DocMem, jint index)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jfieldID fid;
	int ErrorCode, OutputCode, NumberBytes, i;
	void *Phrase;
	char *SingleBytePhrase;
	unsigned short int *DoubleBytePhrase;
	jbyteArray arr_return;

	fid = (*env)->GetFieldID(env, cls, "int_output_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return NULL;
	}
	OutputCode = (*env)->GetIntField(env, obj, fid);
	fid = (*env)->GetFieldID(env, cls, "int_last_return_code", "I");
	if (fid == 0)
	{	// set error code in Java to -1 (unknown error) and return
		(*env)->SetIntField(env, obj, fid, -1);
		return NULL;
	}
	
	ErrorCode = ExtrGetHighlightByIndex((void *)DocMem, index, (void **)&Phrase);
	(*env)->SetIntField(env, obj, fid, ErrorCode);

	if (ErrorCode != 0)
	{	// ensure semething is returned
		return NULL;
	}

	if (OutputCode == 2)
	{	// unicode case
		DoubleBytePhrase = (unsigned short int*) Phrase;
		for (i = 0; DoubleBytePhrase[i] != 0; i++); // get number of characters
		NumberBytes = i * 2; // get number of bytes
	}
	else
	{
		NumberBytes = strlen((char *)Phrase);
	}


	SingleBytePhrase = (char *) Phrase;
	
	arr_return = (*env)->NewByteArray(env, NumberBytes);
	(*env)->SetByteArrayRegion(env, arr_return, 0, NumberBytes, SingleBytePhrase);

	return arr_return;
}


int unsigned_array_len(unsigned short int *arr)
{
	int i = 0;
	if (arr != NULL)
	{
		for (i = 0; arr[i] != 0; i++);
	}
	return i;
}
